22.2.1节,"Specail Bean Types In the WebApplicationContext"和22.2.2,"Default DispathcerServlet Configuration"介绍了Spring MVC的特殊的bean和DispatcherServlet
使用的默认实现。在这节,你将会学到另外两种配置Spring MVC的方法。叫做MVC Java配置和MVC XML命名空间。
MVC Java配置和MVC命名空间提供了相似的默认配置来覆盖DispatcherServlet
的默认值。目的是为了让你不必要为大部分应用程序配置相同的配置,并且也提供更上层的构造方式来配置Spring MVC,以这样的方式作为起点更简单,也不需要了解底层的配置。
你可以根据个人的偏好选择MVC Java配置或是MVC命名空间
。你将会在之后看到,MVC Java配置更容易看到底层的配置并且可以直接对创建的Spring MVC bean更加细粒度的定义。让我们从开始学起。
在你的@Configuration
类上添加@EnableWebMvc
可以启用MVC Java配置:
@Configuration
@EnableWebMvc
public class WebConfig {
}
如果想在XML中实现这点,可以在你的DispatcherServlet上下文中(如果你没有定义DispathcerServlet上下文的话,可以在根上下文中)使用mvc:annotation-driven
元素:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
</beans>
上面注册了一个RequestMappingHandlerMapping
,一个RequestMappingHandlerAdapter
和一个ExceptionHandlerExceptionResolver
(以及其他),用来支持通过带注解的控制器方法(比如@RequestMapping
,`@ExceptionHandler
等等)处理请求。
它也激活了下面这些功能:
1. 除了JavaBeans PropertyEditors的数据绑定之外,通过ConversionService实例进行Spring 3 风格的类型转换。
2. 通过ConversionService
使用@NumberFormat
注解对格式化Number字段支持。
3. 通过@DateTimeFormat
注解支持Date
,Calendar
,Long
以及Joda Time字段的格式化。
4. 如果类路径下存在JSR-303的提供者,可以支持通过@Valid
验证@Controller
的输入。
5. HttpMesageConvter
支持@RequestMapping
或@ExceptionHandler
方法中的@RequestBody
方法参数和@RequestBody
方法返回值。
下面是mvc:annotation-driven设置的完整的HttpMessageConverters列表:
a.ByteArrayHttpMessageConverter
转换字节数组。
b.StringHttpMessageConverter
转换字符串。
c.ResourceHttpMessageConverter
将所有的媒体类型和org.springframework.core.io.Resource
互转。
d.SourceHttpMessageConverter
用来转javax.xml.transform.Source
。
e.FormHttpMessageConverter
用来在表单数据和MultiValueMap<String, String>
之间互转。
f.Jaxb2RootElementHttpMessageConverter
用来在Java对象和XML之间互转——它会在类路径下JAXB2存在且Jackson 2 XML extension不存在时被添加。
g.MappingJackson2HttpMessageConverter
转换JSON——在Jackson2存在类路径下的时候会被添加。
h.MappingJackson2XmlHttpMessageConverter
用来转换XML——在类路径下存在Jackson 2 XML extension时被添加。
i.AtomFeedHttpMessageConverter
转换Atom feeds——当类路径下存在Rome时被添加。
j.RssChannelHttpMessageConverter
转换RSS feeds——当类路径下存在Rome时被添加。
见22.16.12节,"Message Converters"了解更多馆续自定义这些默认的转换器。
Jackson JSON和XML转换器是由
Jackson2ObjectMapperBuilder
创建的ObjectMapper
实例创建的,目的是提供更好的默认配置。
这个构造器使用下面的方式自定义Jackson的默认属性:
1.禁用DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
。
2.禁用MapperFeature.DEFAULT_VIEW_INCLUSION
。
如果下面这个模块在类路径下被检测到,那么也会被自动注册:
1.jackson-datatype-jdk7:提供对诸如java.nio.file.Path
这样的Java 7的支持。
2.jackson-datatype-joda:支持Joda-Time类型。 3.jackson-datatype-jsr310:支持Java 8 Date & Time API类型。
4.jackson-datatype-jdk8:支持其他Java 8类型,比如Optional
。
你可以通过轻易的实现WebMvcConfigurer
或是继承WebMvcConfigurerAdapter
并覆盖你需要的方法来在Java中自定义默认的配置:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Override configuration methods...
}
要自定义<mvc:annotation-driven/>
的默认配置,请检查它支持的属性和子元素。你可以查看Spring MVC XML schema或是使用你IDE的代码提示功能查看它可用的属性和子元素。
默认内置Number
和Date
类型的格式化器提供了对@NumberFormat
和@DateTimeFormat
注解的支持。如果Joda Time存在于类路径中,则还会安装队Joda Time格式化的全面支持。为了注册formatters和converters,你可以覆盖addFormatters
方法:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
如果在MVC命名空间中添加了<mvc:annotation-driven>
,相同的默认配置也会被应用。如果你想注册自定义的formatters和converters,只需要提供ConversionService
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.MyConverter"/>
</set>
</property>
<property name="formatters">
<set>
<bean class="org.example.MyFormatter"/>
<bean class="org.example.MyAnnotationFormatterFactory"/>
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.example.MyFormatterRegistrar"/>
</set>
</property>
</bean>
</beans>
更多关于使用FormatterRegistrars见第9.6.4节,"FormatterRegistrar SPI"和
FormattingConversionServiceFactoryBean
。
Spring提供了Validator接口用来在应用程序中任何一层中校验。在Spring MVC中,你可以用一个全局的Validator
实例配置,当控制器方法参数中有@Valid
或是@Validated
时,该实例就会被使用,或者通过@InitBinder
方法在控制器内部创建本地Validator
。全局和本地的校验器可以组合起来提供复合校验。
Spring也通过LocalValidatorFactoryBean
支持了JSR-303/JSR-349 Bean Validation,LocalValidatorFactoryBean
用来将Springorg.springframework.validation.Validator
接口适配成Bean Validation javax.validation.Validator
约定。这个类可以插入Spring MVC作为全局的校验器,这将在下节描述。
默认情况下,在Spring MVC中使用@EnableWebMvc
或是<mvc:annotation-driven>
时,如果类路径下存在Bean Validation提供者(比如Hibernate Validator),会通过LocalValidatorFactoryBean
自动注册Bean Validation验证的支持。
有时候将
LocalValidatorFactoryBean
注入到控制器或者其他类中会让代码便捷。最简单的方式就是声明你自己的@Bean
并加上@Primary
避免和MVC Java Config提供的冲突。如果你喜欢使用MVC Java配置,你需要覆盖WebMvcConfigurationSupport
的mvcValidator
方法,并声明方法显示的返回LocalValidatorFactory
而不是Validator
。见22.16.13,"Advanced Customizations with MVC Java Config"获得如何拓展配置的信息。
你可以选择配置你自己的全局Validator
实例:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public Validator getValidator(); {
// return "global" validator
}
}
或者在XML中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="globalValidator"/>
</beans>
为了将本地校验器结合全局校验器使用,只需要简单添加一个或多个本地的校验器:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
通过这些简单配置,无论何时出现了Valid
或是Validated
方法参数,它都会被配置的校验器校验。任何校验失败都会被暴露在通过方法参数传递过来的BindResult
中,并且也可以在Spring MVC HTML视图被渲染。
你可以为所有进来的请求或是某些特定的URL路径的请求配置HandlerInterceptors
或是WebRequestInterceptors
。
下面是在Java中注册拦截器的例子:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
或者是在XML中使用<mvc:interceptors>
元素:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
你可以配置Spring MVC如何探测请求的媒体类型。有效的选择是在URL路径中检查文件拓展名,检查"Accept"头,或是特定的查询参数,或者是没有指定请求的时候返回默认的内容类型。默认的请求URI的路径拓展名会先被检查然后在检查"Accept"头。
如果类路径上存在对应的依赖,那么MVC Java配置和MVC命名空间会默认注册json
,xml
,rss
,atom
。其他的路径拓展媒体类型映射可以通过显式注册实现,这也具有将它们列入白名单防止RFD攻击的效果(详见"Suffix Pattern Matching and RFD")。
下面是一个通过MVC Java配置自定义内容选项的例子:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
}
在MVC命名空间中,<mvc:annotation-driven>
元素有一个content-negotiation-manager
属性,该属性需要一个ContentNegotiationManager
,这又可以通过ContentNegotiationManagerFactoryBean
:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
如果不适用MVC Java配置或是MVC命名空间,你需要创建一个ContentNegotiationManager
的实例,并用它来配置RequestMappingHandlerMapping
来实现请求的映射,以及RequestMappingHandlerAdapter
和ExceptionHandlerExceptionResolver
来实现内容协商。
请注意,ContentNegotiatingViewResolver
现在也可以用ContentNegotiationManager
配置,因此你可以在Spring MVC中使用一个实例。
在更高级的情况下,配置多个ContentNegotiationManager
实例可能会很有用,这些实例可以包含自定义的ContentNegotiationStrategy
的实现。比如,你可以用ContentNegotiationManager
配置一个用来处理请求媒体类型为"application/json"
的ExceptionHandlerExceptionResolver
。或者当没有指定请求的媒体类型时,你希望插入一个自定义的策略来选择默认的媒体类型(比如,XML或是JSON)。
这是一个定义ParameterizableViewController
的快捷方式,可以在调用时立即转发到视图。它用来在生成响应前没有Java控制器逻辑需要执行的情况。
比如,将"/"
请求转发到"home"
的Java实现:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
在XML中可以通过<mvc:view-controller>
元素实现相同的功能:
<mvc:view-controller path="/" view-name="home"/>
MVC配置简化了视图解析器的配置。
下面是Java配置的一个例子,它使用FreeMarker HTML模板和Jackson作为JSON呈现的默认View
:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
在XML也可以配置:
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:jsp/>
</mvc:view-resolvers>
注意,FreeMarker,Velocity,Tiles,Groovy Markup和其他模板也需要配置底层的视图技术。
MVC命名空间提供了专门的元素。比如,FreeMarker:
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>
在Java配置中,只需要添加对应的“配置”Bean:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker().cache(false);
}
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/");
return configurer;
}
}
这个选项允许Resource
列表中特定URL的静态资源请求被ResourceHttpRequestHandler
处理。这提供了一种便捷的方式来处理web应用程序根路径以外的静态资源,包括类路径上的。cache-period
属性可以用来设置过期的时间(建议为Page Speed和YSlow等优化工具的值设置为1年)一直与让他们更有效的被客户端使用。该处理器还可正确评估Last-Modified
标头(如果存在),以便根据情况返回304
状态码,从而避免由客户端缓存的资源造成不必要的开销。比如,想要使得web应用根路径下的public-resource
中的/resoures/**
来处理资源请求,你可以这么使用:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
}
如果是在XML中,你可以这么做:
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
为了让这些资源的有效期为1年,确保最大化使用浏览器缓存并降低浏览器的HTTP请求,你可以:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
}
}
或是在XML中:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
更多信息,见HTTP caching support for static resources。
mapping
属性一定要是Ant风格的样式,可以被SimpleUrlHandlerMapping
使用,location
属性一定要指定至少一个合法的资源路径。多个资源路径可以通过逗号分隔符属性列表来指定。对一个请求,将按照指定顺序来检查指定路径下是否存在资源。比如,你想让来自web应用根路径和类路径下任何jar中的/META-INF/public-web-resources/
的资源被启用,可以:
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
}
}
在XML中。你可以:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>
当部署应用程序的新版本时可能会更改资源时,建议将版本字符串并入用于请求资源的映射模式,以便强制客户端请求新部署的应用程序资源版本。框架内置了对带版本的URL的支持,可以在资源处理中配置资源链来启用。这个资源链由多个ResourceResolver
实例组成,后面又跟着一个或多个ResourceTransformer
实例。他们一起提供了解析和资源转换的功能。
内置的VersionResourceResolver
可以配置不同的策略。比如,FixedVersionStrategy
可以使用一个属性,一个日期,或是其他作为版本。ContentVersionStrategy
使用由资源的内容计算而得MD5码(也叫“指纹”URL)。请注意,在服务资源时,VersionResourceResolver
将自动使用已解析的版本字符串作为HTTP ETag标头值。
ContentVersionStrategy
是一个很好的默认选择,除非无法使用它时(例如,javascript模块加载器)。你可以想下面这样为不同的样式配置不同的版本策略。请记住,计算基于内容的版本代价是昂贵的,因此在生产环境中应该启用医院连缓存。
Java配置例子:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public-resources/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
XML的例子:
<mvc:resources mapping="/resources/**" location="/public-resources/">
<mvc:resource-chain>
<mvc:resource-cache/>
<mvc:resolvers>
<mvc:version-resolver>
<mvc:content-version-strategy patterns="/**"/>
</mvc:version-resolver>
</mvc:resolvers>
</mvc:resource-chain>
</mvc:resources>
为了上面的配置能够生效,应用程序还需要呈现带版本的URL。最简单的方式是配置ResourceUrlEncodingFilter
来封装响应并覆盖他的encodeURL
方法。这在JSPs,FreeMarker,Velocity,和任意其他调用响应的encodeURL
方法的视图科技中都可以使用。应用也可以选择直接注入和使用ResourceUrlPRovider
bean,它会自动被MVC Java配置和MVC名某个空间声明。
Webjars也支持WebJarsResourceResolver
,当类路径上存在"org.webjars:webjars-locator"
库是时,它会被自动注册。这个解析器允许资源链解析版本不可知的库,比如HTTP GET请求"GET /jquery/jquery.min.js"
会返回"/jquery/1.2.0/jquery.min.js"
。它对模板中重写的资源URL同样有效<script src="/jquery/jquery.min.js"/> → <script src="/jquery/1.2.0/jquery.min.js"/>
这允许将DispatcherServlet
映射到“/”(从而覆盖容器默认Servlet的映射),同时仍允许静态资源请求由容器的默认Servlet处理。它使用“/**”的URL映射和比其他优先级的URL映射来配置DefaultServletHttpRequestHandler
。
这个处理器将会分发所有的请求到默认的Servlet,因此它要在其他所有的URLHandlerMappings
之后。如果你使用<mvc:annotation-driven>
或是你选择设置自己的HandlerMapping
实例,请确保将它的order
属性设置的比DefaultServletHttpRequestHandler
的值(为Integer.MAX_VALUE
)要小。
使用默认的设置启用这个特性:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
或是在XML中:
<mvc:default-servlet-handler/>
对于重写“/”Servlet映射的警告是默认的RequestDispatcher
是通过名称而不是通过路径来检索。DefaultServletHttpRequestHandler
会在容器启动时尝试使用大部分Servlet容器(包括Tomcat, Jetty,GlassFish,JBoss,Resin,Weblogic和WebSphere)已知的名称列表来自动检测默认的默认的Servlet。如果默认的Servlet被自定义配置成了不同的名字,或是使用一个不同Servlet容器,而这个容器默认的Servlet名字并不知道,那么就需要显式的提供这个Servlet的名字,像下面的代码:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
或是在XML中:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
它允许你自定义URL映射和路径匹配相关的设置。详细细节请看PatchMatchConfirgurer API。
下面是Java配置的例子:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseSuffixPatternMatch(true)
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper());
}
@Bean
public UrlPathHelper urlPathHelper() {
//...
}
@Bean
public PathMatcher antPathMatcher() {
//...
}
}
在XML中,可以用<mvc:path-matching>
元素:
<mvc:annotation-driven>
<mvc:path-matching
suffix-pattern="true"
trailing-slash="false"
registered-suffixes-only="true"
path-helper="pathHelper"
path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
在Java配置中自定义HttpMessageConverter
可以通过重写configureMesageConverters()
替换Spring MVC创建的默认的转换器,或是如果你只想自定义它们或是添加额外的转换器,可以通过重写extendMessageConverters()
。
下面是添加Jackson JSON和用一个带自定义的ObjectMapper
的XML转换器替换默认转换器的例子:
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
}
}
这个例子中,Jackson2ObjectMapperBuilder
用来为MappingJackson2HttpMessageConverter
和MappingJackson2XmlHttpMessageConverter
创建一个通用的配置,并启用了缩进空能,自定义日期格式和注册jackson-module-parameter-names来支持访问参数名称(Java 8的特性)。
通过Jackson XML启用缩进支持除了需要
jackson-dataformat-xml
之外还要woodstox-core-asl
依赖。
其他可用的感兴趣的Jackson模块:
1. jackson-datatype-money:支持javax.money
类型(非官方模块)
2. jackson-datatype-hibernate:支持Hibernate特定的类型和属性(包括惰性加载切面)
XML中也可以做到这些配置:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="xmlMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true"
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>
正如你从上面的例子中所见,MVC Java配置和MVC命名空间提供了高层级的构建,不需要你知道底层为你所创建的bean的知识。它让你更关注你应用的需求。然而,有时候你需要更细粒度的控制或是你可能希望了解底层的配置。
为了更细粒度的控制,首先是看底层所创建的bean。在MVC Java配置中,你可以看Java文档和WebMvcConfigurationSupport
的@Bean
方法。这个类中的配置通过@EnableWebMvc
注释自动引入。事实上,如果你打开@EnableWebMvc
,你会看见@Import
声明。
然后你需要自定义WebMvcConfigurationSupport
中创造的属性或是用你自己的实例。这需要两方面——移除@EnableWebWvc
注释为了防止引入,然后继承DelegatingWebMvcConfiguration
,WebMvcConfigurationSupport
的子类。下面是一个例子:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
@Override
public void addInterceptors(InterceptorRegistry registry){
// ...
}
@Override
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// Create or let "super" create the adapter
// Then customize one of its properties
}
}
一个应用程序应该只有一个继承自
DelegatingWebMvcConfiguration
的配置或是一个@EnableWebMvc
注解的类,因为它们都会注册一些相同的底层的bean。
使用这种方式修改bean并不会影响你使用本节前面所展示的更层次的构建。WebMvcConfigurerAdapter
子类和WebMvcConfigurer
实现任然会被使用。
在MVC命名空间中用你自己创建的配置实现更细粒度的控制有点难。
如果你需要这么做,请考虑配置一个BeanPostProcessor
来根据类型检测你需要的bean,并修改它们的属性而不是拷贝一份它提供的配置。比如:
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
// Modify properties of the adapter
}
}
}
注意,为了MyPostProcessor
能被检测到,它需要被包含在<component scan>
中,或者你也可以在XML中显式做Bean的声明。